package holdem;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import java.util.ArrayList;
import java.util.Iterator;

import java.util.List;

/**
 *
 * @author qipai, Jon
 */
public abstract class NestedIntegerList
	extends ListInt {
    private List<ListInt> list;
    private final String  methodPrefix = "wm_";

    //~--- methods ------------------------------------------------------------

    public Iterator<ListInt> iterator() {
	return list.iterator();
    }

    public final Integer size() {
	if (list == null) {
	    get(0);
	}

	return list.size();
    }

    /**
     *
     * @param index
     * @return
     */
    public ListInt get(Integer index) {
	if (list == null) {
	    list = new ArrayList();

	    Field[] fs = getClass().getDeclaredFields();

	    /*
	     * Integer, Boolean, enum -> IntegerCell
	     * List<>, String -> as is
	     *
	     */
	    for (int i = 0; i < fs.length; i++) {
		try {
		    Field f = fs[i];

		    f.setAccessible(true);

		    // filter system fields and string fields
		    if (f.getName().startsWith("$")
			    || (f.get(this) instanceof String)) {
			continue;
		    }

		    // if is static
		    // if (Modifier.isStatic(f.getModifiers())) {
		    if (f.get(this) instanceof List) {
			final String myName = f.getName();
			final List   myList = (List) f.get(this);

			list.add(new NestedIntegerList() {
			    @Override
			    public ListInt get(Integer index) {

				// ASSUMPTION : ArrayList only contains ListInt
				return (ListInt) myList.get(index);
			    }
			    @Override
			    public Integer getSize() {
				return myList.size();
			    }

			    @Override
			    public String getName() {
				return myName;
			    }
			});
		    } else if (f.get(this) instanceof NestedIntegerList) {
			list.add((NestedIntegerList) f.get(this));

		    } else {
			ListInt o = (ListInt) IntegerCell.make(this, f);

			if (o != null) {
			    list.add(o);
			} else {

			    // cannot make?
			    System.err.println("???");
			}
		    }
		} catch (Exception ex) {
		    ex.printStackTrace();
		}

	    }

	    for (Method m : getAllSetMethods()) {
		final Method n = m;

		list.add(new ListInt() {

		    @Override
		    public Boolean isSymbol() {
			return true;
		    }

		    @Override
		    public Boolean isList() {
			return false;
		    }

		    @Override
		    public ListInt get(Integer i) {
			return null;
		    }

		    @Override
		    public Integer getSymbol() {
			try {
			    return (Integer) n.invoke(this);
			} catch (Exception ex) {
			    return null;
			}
		    }

		    @Override
		    public void set(Integer I) {}

		    @Override
		    public Integer getSize() {
			return 1;
		    }

		    @Override
		    public String getName() {
			return n.getName();
		    }
		});
	    }
	}

	if (list.isEmpty()) {
	    return null;
	}

	return list.get(index);
    }

    @Override
    public Boolean isSymbol() {
	return false;
    }

    @Override
    public Boolean isList() {
	return true;
    }

    @Override
    public Integer getSymbol() {
	return null;
    }

    @Override
    public void set(Integer I) {}

    @Override
    public Integer getSize() {
	return size();
    }

    public String getName() {
	return this.getClass().getSimpleName();
    }

    private List<Method> getAllSetMethods() {
	Method[]     m       = this.getClass().getMethods();
	List<Method> methods = new ArrayList<Method>();

	for (int i = 0; i < m.length; i++) {
	    if (m[i].getName().startsWith(methodPrefix)) {
		methods.add(m[i]);
	    }
	}

	/*
	 * Class returnType = methods.get(0).getReturnType();
	 * Class parameterTypes = methods.get(0).getParameterTypes();
	 */
	return methods;
    }

}
